﻿using System;
using System.ComponentModel.Design;
using System.Diagnostics;
using System.IO;
using EnvDTE;
using Expect.Core.Config;
using Expect.VisualStudio.Extensions.Services;
using Microsoft.VisualStudio.Shell;
using Microsoft.Win32;

namespace Expect.VisualStudio.Extensions.Commands.Handlers
{
    
    public abstract class ReportConsoleCommand : OleMenuCommand
    {
        protected VsOutputWriter _writer;

        protected Project _project;

        protected ReportElement _reportCfg;

        protected string _source;

        protected string _sourcedir;

        protected string _projectpath;

        protected string _reportAppPath;

        protected IExpectPackage _pkg;

        public ReportConsoleCommand(IExpectPackage pkg,int idCommand)
            : base(Callback, new CommandID(Guids.guidExpect_ExtensionsCmdSet, idCommand))
        {
            _pkg = pkg;
            this.BeforeQueryStatus += new EventHandler(Command_BeforeQueryStatus);
        }

        protected object GetVSService(Type t)
        {
            return _pkg.GetVSService(t);
        }

        protected bool Ask(string msg)
        {
            return CommandSet.Ask(_pkg, msg);
        }

        protected void ShowMessage(string msg)
        {
            CommandSet.ShowMessage(_pkg, msg);
        }

        void Command_BeforeQueryStatus(object sender, EventArgs e)
        {
            IExpectVSService expectService = (IExpectVSService)GetVSService(typeof(SExpectVSService));
            var filename = expectService.CurrentFile().ToLower();
            var dte = (EnvDTE80.DTE2)GetVSService(typeof(Microsoft.VisualStudio.Shell.Interop.SDTE));
            
            _project = null;
            _reportCfg = null;
            Visible = false;

            var item = dte.SelectedItems.Item(1).Project;
            if (item != null)
            {
                if (!this.GetProject(expectService, item, filename)) return;
            }
            else
            {
                Visible = false;
                return;
            }

            string assname = _project.Properties.Item("OutputFileName").Value.ToString();
            
            string outputPath = _project.ConfigurationManager.ActiveConfiguration.Properties.Item("OutputPath").Value.ToString();
            _projectpath = Path.GetDirectoryName(_project.FileName);
            _sourcedir = Path.Combine(_projectpath, outputPath);
            _source = Path.Combine(_sourcedir, assname);

            GetReportAppPath();
            if (string.IsNullOrEmpty(_reportAppPath) || !File.Exists(_reportAppPath))
            {
                Visible = false;
                return;
            }
        }

        private bool GetProject(IExpectVSService expectService, Project project, string filename)
        {
            string projectDir = Path.GetDirectoryName(project.FileName).ToLower();
            if (!projectDir.EndsWith("\\"))
            {
                projectDir = projectDir + "\\";
            }
            if (!filename.EndsWith("\\"))
            {
                filename = filename + "\\";
            }
            if (projectDir == filename)
            {
                var config = expectService.GetConfigurationFor(project);
                if (config != null && config.Report != null && !string.IsNullOrEmpty(config.Report.TemplateFile))
                {
                    this._project = project;
                    this._reportCfg = config.Report;
                    this.Visible = true;
                    return true;
                }
            }

            return false;
        }

        private static void Callback(object sender, EventArgs args)
        {
            var current = (ReportConsoleCommand)sender;
            current.Execute();
        }

        private void PrepareReport()
        {
            _writer = new VsOutputWriter(_pkg, "Expect");
            _writer.Clear();
            _writer.WriteLine("Expect " + DateTime.Now.ToLongDateString());
            
            //WriteProperties();

            
        }

        private void WriteProperties()
        {
            foreach (Property property in this._project.Properties)
            {
                try
                {
                    if (property.Value != null)
                    {
                        this._writer.WriteLine(property.Name + "=" + (string)property.Value.ToString());
                    }
                }
                catch (Exception)
                {
                }
            }
            this._writer.WriteLine(string.Empty);
            foreach (Property property in this._project.ConfigurationManager.ActiveConfiguration.Properties)
            {
                try
                {
                    if (property.Value != null)
                    {
                        this._writer.WriteLine(property.Name + "=" + (string)property.Value.ToString());
                    }
                }
                catch (Exception)
                {
                }
            }
        }

        private void Execute()
        {
            PrepareReport();
            if (!Validate()) return;

            var dte = (EnvDTE80.DTE2)GetVSService(typeof(Microsoft.VisualStudio.Shell.Interop.SDTE));
            dte.Solution.SolutionBuild.BuildProject(
                _project.ConfigurationManager.ActiveConfiguration.ConfigurationName,
                _project.UniqueName, 
                true);
            if (dte.Solution.SolutionBuild.LastBuildInfo != 0)
            {                
                return;
            }
            
            System.Diagnostics.Process p = new System.Diagnostics.Process();
            p.StartInfo = new ProcessStartInfo(_reportAppPath);
            p.StartInfo.UseShellExecute = false;
            p.StartInfo.RedirectStandardOutput = true;
            p.StartInfo.WorkingDirectory = _sourcedir;
            p.StartInfo.Arguments = GetCommandArguments();
            p.StartInfo.CreateNoWindow = true;
            _writer.Show();
            _writer.WriteLine("Running " + p.StartInfo.FileName + " " + p.StartInfo.Arguments);
            p.Start();
            string line = null;
            while (!p.HasExited || ((line = p.StandardOutput.ReadLine()) != null))
            {
                if (!string.IsNullOrEmpty(line))
                {
                    _writer.WriteLine(line);
                }

                System.Threading.Thread.Sleep(50);
            }

            if (p.ExitCode != 0)
            {
                ShowMessage(GetErrorMessage());
                return;
            }

            this.AfterExecute();
        }

        protected virtual void AfterExecute()
        {
            
        }

        protected abstract string GetErrorMessage();
        protected abstract string GetCommandArguments();

        private void OpenDocument()
        {
            System.Diagnostics.Process p = new System.Diagnostics.Process();
            p.StartInfo = new ProcessStartInfo(_reportCfg.OutputFile);
            p.StartInfo.WorkingDirectory = _sourcedir;

            p.Start();
        }

        protected abstract bool Validate();
        

        private void GetReportAppPath()
        {
            if (!string.IsNullOrEmpty(_reportCfg.ReportApp))
            {
                if (!File.Exists(_reportCfg.ReportApp) && _reportCfg.ReportApp.StartsWith("..\\"))
                {
                    var curdir = Directory.GetCurrentDirectory();
                    try
                    {
                        Directory.SetCurrentDirectory(_projectpath);
                        var path = Path.GetFullPath(_reportCfg.ReportApp);
                        if (File.Exists(path))
                        {
                            _reportAppPath = path;
                        }
                    }
                    finally
                    {
                        Directory.SetCurrentDirectory(curdir);
                    }
                }
                else
                {
                    _reportAppPath = _reportCfg.ReportApp;
                }
            }

            if (string.IsNullOrEmpty(_reportAppPath))
            {
                var dte = (EnvDTE80.DTE2)GetVSService(typeof(Microsoft.VisualStudio.Shell.Interop.SDTE));
                var key = Registry.LocalMachine.OpenSubKey("Software\\Expect");
                if (key != null)
                {
                    //VS2010 test framework must run on .Net 4, we select report app dependending on VS version
                    if (dte.Version == "9.0")
                    {
                        _reportAppPath = key.GetValue("Report35").ToString();
                    }
                    else
                    {
                        _reportAppPath = key.GetValue("Report40").ToString();
                    }
                }
            }
        }
    }
}
